Load Data

# load experiments info
experiments <- readxl::read_excel(file.path("data", "experiments.xlsx"))

# load concentration data
conc_data <- readxl::read_excel(file.path("data", "data.xlsx"), sheet = "conc_data")

# load iso data
iso_data <- readxl::read_excel(file.path("data", "data.xlsx"), sheet = "iso_data")

# growth data
growth_data <- readxl::read_excel(file.path("data", "data.xlsx"), sheet = "growth_data")

Prepare Data

# prepare concentration data
conc_data_w_t0 <- 
  conc_data %>% 
  # determine t0 concentrations and ln space offset
  group_by(exp_id, culture) %>% 
  mutate(
    NO3_0.mM = NO3.mM[timepoint == 0],
    ln_NO3 = log(NO3.mM / NO3_0.mM),
  ) %>% 
  ungroup()

# prepare isotope data
iso_data_w_t0 <-
  iso_data %>%
  # determine t0 isotopic compositions
  mutate(
    d15N_0.permil = mean(d15N.permil[timepoint == 0]),
    d15N_0_sd.permil = sd(d15N.permil[timepoint == 0]),
    d18O_0.permil = mean(d18O.permil[timepoint == 0]),
    d18O_0_sd.permil = sd(d18O.permil[timepoint == 0]),
    t0_n = sum(timepoint == 0)
  ) %>%
  # determine isotopic offsets from t0
  mutate(
    D_d15N = d15N.permil - d15N_0.permil,
    D_d18O = d18O.permil - d18O_0.permil,
    ln_d15N = log((d15N.permil/ 1000 + 1) / (d15N_0.permil /1000 +1)),
    ln_d18O = log((d18O.permil/ 1000 + 1) / (d18O_0.permil /1000 +1))
  )

# cache
write_rds(conc_data_w_t0, file.path("cache", "conc_data_w_t0.rds"))
write_rds(iso_data_w_t0, file.path("cache", "iso_data_w_t0.rds"))

Calculate fractionation factors

# calculate fractionation factors for all culture replicates with
# more than 2 data points to get an error estimate
# see figures S3 and S4 for visual representation
eps_data <-
  inner_join(conc_data_w_t0, iso_data_w_t0, by = c("exp_id", "culture", "timepoint")) %>% 
  group_by(exp_id, culture) %>% filter(n() > 2L) %>% ungroup() %>% 
  nest(data = c(-exp_id, -culture)) %>%
  mutate(
    n_datapoints = map_int(data, nrow),
    fit_15N = map(data, ~lm(ln_d15N ~ ln_NO3, data = .x)),
    coefs_15N = map(fit_15N, tidy),
    summary_15N = map(fit_15N, glance),
    eps15N.permil = map_dbl(coefs_15N, ~filter(.x, term == "ln_NO3")$estimate * 1000),
    eps15N_se.permil = map_dbl(coefs_15N, ~filter(.x, term == "ln_NO3")$std.error * 1000),
    fit_18O = map(data, ~lm(ln_d18O ~ ln_NO3, data = .x)),
    coefs_18O = map(fit_18O, tidy),
    summary_18O = map(fit_18O, glance),
    eps18O.permil = map_dbl(coefs_18O, ~filter(.x, term == "ln_NO3")$estimate * 1000),
    eps18O_se.permil = map_dbl(coefs_18O, ~filter(.x, term == "ln_NO3")$std.error * 1000)
  ) %>% 
  select(-data, -starts_with("fit"), -starts_with("coefs"), -starts_with("summary"))

# cache
write_rds(eps_data, file.path("cache", "eps_data.rds"))
eps_data

Calculate \(\epsilon^{18}O\) : \(\epsilon^{15}N\) coupling

# calculate coupling across all replicates in the same medium
# see figure S5 for visual representation
coupling_data <-
  iso_data_w_t0 %>% 
  left_join(experiments, by = "exp_id") %>% 
  nest(data = c(-strain_id, -medium)) %>% 
  mutate(
    n_datapoints = map_int(data, nrow),
    fit = map(data, ~lm(ln_d18O ~ ln_d15N, data = .x)),
    coefs = map(fit, tidy),
    summary = map(fit, glance),
    ON_ratio = map_dbl(coefs, ~filter(.x, term == "ln_d15N")$estimate),
    ON_ratio_se = map_dbl(coefs, ~filter(.x, term == "ln_d15N")$std.error)
  ) %>% 
  select(strain_id, medium, n_datapoints, ON_ratio, ON_ratio_se)

# cache
write_rds(coupling_data, file.path("cache", "coupling_data.rds"))
coupling_data

Calculate growth rates

# calculate growth rates for each replicate
growth_rates_data <- 
  growth_data %>% 
  #group_by(exp_id, culture) %>% 
  estimate_growth_curve_parameters(
    time = hour, N = OD,
    group_by = c(exp_id, culture)
  ) %>% 
  select(
    exp_id, culture, n_datapoints, hour_min = time_min, hour_max = time_max,
    OD0 = N0, # OD at t0
    K = K, # carrying capacity (i.e. OD max)
    mu.1_hr = r, # growth rate in 1/hr
    mu_se.1_hr = r_se # standard error of the growth rate
  )
## Info: estimating growth parameters for 30 growth curves (grouped by 'exp_id', 'culture')... 29 curves fitted successfully.
# cache
write_rds(growth_rates_data, file.path("cache", "growth_rates_data.rds"))
growth_rates_data